C++ 的关键字:
- alignas
- alignof
- and
- and_eq
- asm
- atomic_cancel
- atomic_commit
- atomic_noexcept
- auto
- bitand
- bitor
- bool
- break
- case
- catch
- char
- char8_t
- char16_t
- char32_t
- class
- co_await
- co_return
- co_yield
- compl
- concept
- const
- consteval
- constexpr
- constinit
- const_cast
- continue
- decltype
- default
- delete
- do
- double
- dynamic_cast
- else
- enum
- explicit
- export
- extern
- false
- float
- for
- friend
- goto
- if
- inline
- int
- long
- mutable
- namespace
- new
- noexcept
- not
- not_eq
- nullptr
- operator
- or
- or_eq
- private
- protected
- public
- register
- reinterpret_cast
- requires
- return
- short
- signed
- sizeof
- static
- static_assert
- static_cast
- struct
- switch
- synchronized
- template
- this
- thread_local
- throw
- true
- try
- typedef
- typeid
- typename
- union
- unsigned
- using
- virtual
- void
- volatile
- wchar_t
- while
- xor
- xor_eq
C++14 关键字使用演示
-
auto (类型推导)
#include
#includeint main() {
// 自动推导出 i 的类型为 int
auto i = 10;// 自动推导出 v 的类型为 std::vector
auto v = std::vector{1, 2, 3};// 使用 auto 简化迭代器类型
for (auto it = v.begin(); it != v.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;return 0;
} -
decltype (类型获取)
#include
int main() {
int a = 10;
// 获取 a 的类型并定义相同类型的变量 b
decltype(a) b = 20;// 使用 decltype 推导出函数返回值类型
auto sum = [](int x, int y) -> decltype(x + y) { return x + y; };std::cout << "a + b = " << sum(a, b) << std::endl;
return 0;
} -
constexpr (常量表达式)
#include
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}int main() {
// 在编译期计算阶乘
constexpr int result = factorial(5);// 使用常量表达式初始化数组大小
int arr[result] = {};std::cout << "5! = " << result << std::endl;
return 0;
} -
lambda 表达式 (匿名函数)
#include
#include
#includeint main() {
std::vector v = {1, 5, 3, 2, 4};// 使用 lambda 表达式排序
std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; });// 使用 lambda 表达式输出
std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; });
std::cout << std::endl;return 0;
}
其他重要关键字:
-
default/delete (控制默认函数生成): 控制编译器是否生成默认构造函数、拷贝构造函数、赋值运算符等。
-
nullptr (空指针): 更安全的空指针表示,避免与整型 0 混淆。
-
[[deprecated]] (标记废弃): 标记废弃的函数、类或变量,编译器会给出警告。
-
数字分隔符 (提高可读性): 使用单引号分隔数字,例如 1’000’000。
#include // 使用#include指令包含输入输出流库
// 定义一个宏,用于输出调试信息
#define DEBUG(x) std::cout << x << std::endl// 声明一个命名空间
namespace MyNamespace {
// 定义一个类
class MyClass {
public:
// 构造函数
MyClass(int a) : value(a) {}// 声明一个静态成员函数 static void staticFunction() { DEBUG("Static function called"); } // 声明一个常成员函数 void constFunction() const { DEBUG("Const function called with value: " << value); } // 重载运算符 MyClass operator+(const MyClass& other) const { return MyClass(value + other.value); } private: // 声明一个成员变量 int value; };
}
// 主函数
int main() {
// 声明变量
int x = 10;
int y = 20;// 使用if语句 if (x < y) { DEBUG("x is less than y"); } else { DEBUG("x is not less than y"); } // 使用循环 for (int i = 0; i < 5; ++i) { DEBUG("i: " << i); } // 使用指针和动态分配 int* ptr = new int(30); DEBUG("Pointer value: " << *ptr); delete ptr; // 释放动态分配的内存 // 使用命名空间中的类 MyNamespace::MyClass obj1(100); MyNamespace::MyClass obj2(200); // 调用类的静态函数 MyNamespace::MyClass::staticFunction(); // 调用类的常成员函数 obj1.constFunction(); // 使用运算符重载 MyNamespace::MyClass obj3 = obj1 + obj2; obj3.constFunction(); // 使用switch语句 switch (x) { case 10: DEBUG("x is 10"); break; default: DEBUG("x is not 10"); break; } // 返回值 return 0;
}
-
const 关键字:
#include
int main() {
// 定义一个常量
const int MAX_VALUE = 100;// 尝试修改常量,会报错
// MAX_VALUE = 200;std::cout << "MAX_VALUE: " << MAX_VALUE << std::endl;
return 0;
} -
enum 关键字:
#include
enum Color { RED, GREEN, BLUE };
int main() {
Color myColor = GREEN;if (myColor == GREEN) {
std::cout << “Color is GREEN” << std::endl;
}return 0;
} -
struct 关键字:
#include
struct Point {
int x;
int y;
};int main() {
Point p1 = {10, 20};std::cout << “Point: (” << p1.x << ", " << p1.y << “)” << std::endl;
return 0;
} -
union 关键字:
#include
union Data {
int i;
float f;
};int main() {
Data data;
data.i = 10;std::cout << "Integer value: " << data.i << std::endl;
data.f = 3.14f;
std::cout << "Float value: " << data.f << std::endl;
return 0;
} -
typedef 关键字:
#include
typedef int Integer;
int main() {
Integer num = 10;std::cout << "Integer value: " << num << std::endl;
return 0;
} -
volatile 关键字:
#include
volatile int counter = 0;
int main() {
// 在多线程环境中,counter 的值可能会被其他线程修改
// 使用 volatile 关键字,确保每次访问 counter 都从内存中读取
for (int i = 0; i < 10; ++i) {
counter++;
std::cout << "Counter: " << counter << std::endl;
}return 0;
} -
extern 关键字:
// file1.cpp
int global_var = 10;// file2.cpp
#include
extern int global_var;int main() {
std::cout << "Global variable: " << global_var << std::endl;return 0;
} -
explicit 关键字:
#include
class MyClass {
public:
explicit MyClass(int value) : value(value) {}//显式int getValue() const {
return value;
}private:
int value;
};int main() {
// 由于构造函数是 explicit 的,无法隐式转换
// MyClass obj = 10; // 错误// 需要显式调用构造函数
MyClass obj(10);std::cout << "Value: " << obj.getValue() << std::endl;
return 0;
} -
friend 关键字:
#include
class MyClass {
public:
friend void printValue(MyClass obj);MyClass(int value) : value(value) {}
private:
int value;
};void printValue(MyClass obj) {
std::cout << "Value: " << obj.value << std::endl;
}int main() {
MyClass obj(10);
printValue(obj);return 0;
} -
sizeof 关键字:
#include
int main() {
int num = 10;
std::cout << "Size of int: " << sizeof(num) << std::endl;return 0;
} -
nullptr 关键字:
#include
int main() {
int* ptr = nullptr;if (ptr == nullptr) {
std::cout << “Pointer is null” << std::endl;
}return 0;
} -
alignof 关键字:
#include
int main() {
int num = 10;
std::cout << "Alignment of int: " << alignof(num) << std::endl;return 0;
} -
decltype 关键字:
#include
int main() {
int num = 10;
decltype(num) anotherNum = 20;std::cout << "Another number: " << anotherNum << std::endl;
return 0;
} -
noexcept 关键字:
#include
int add(int a, int b) noexcept {
return a + b;
}int main() {
int result = add(10, 20);std::cout << "Result: " << result << std::endl;
return 0;
} -
constexpr 关键字:
#include
constexpr int square(int x) {
return x * x;
}int main() {
constexpr int result = square(5);std::cout << "Result: " << result << std::endl;
return 0;
} -
auto 关键字:
#include
int main() {
auto num = 10; // 自动推断类型为 int
auto str = “Hello”; // 自动推断类型为 const char*std::cout << "Number: " << num << std::endl;
std::cout << "String: " << str << std::endl;return 0;
} -
override 关键字:
#include
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};int main() {
Derived derived;
derived.print();return 0;
} -
final 关键字:
#include
class Base {
public:
virtual void print() final {
std::cout << “Base class” << std::endl;
}
};// 无法继承 Base 类并重写 print() 方法
// class Derived : public Base {
// void print() override; // 错误
// };int main() {
Base base;
base.print();return 0;
} -
using 关键字:
#include
namespace MyNamespace {
int value = 10;
}int main() {
using namespace MyNamespace;std::cout << "Value: " << value << std::endl;
return 0;
} -
delete 关键字:
#include
class MyClass {
public:
MyClass() {
std::cout << “Constructor called” << std::endl;
}~MyClass() {
std::cout << “Destructor called” << std::endl;
}
};int main() {
MyClass* obj = new MyClass();delete obj; // 调用析构函数
return 0;
} -
dynamic_cast 关键字:
#include
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};int main() {
Base* basePtr = new Derived();Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr != nullptr) {
derivedPtr->print();
} else {
std::cout << “Conversion failed” << std::endl;
}return 0;
} -
reinterpret_cast 关键字:
#include
int main() {
int num = 10;
char* charPtr = reinterpret_cast<char*>(&num);std::cout << "Character value: " << *charPtr << std::endl;
return 0;
} -
static_cast 关键字:
#include
int main() {
double d = 3.14;
int i = static_cast(d);std::cout << "Integer value: " << i << std::endl;
return 0;
} -
const_cast 关键字:
#include
int main() {
const int num = 10;int* ptr = const_cast<int*>(&num);
*ptr = 20;
std::cout << "Modified value: " << num << std::endl;
return 0;
} -
typeid 关键字:
#include
#includeclass MyClass {};
int main() {
MyClass obj;std::cout << "Type of object: " << typeid(obj).name() << std::endl;
return 0;
} -
throw 关键字:
#include
#includeint divide(int a, int b) {
if (b == 0) {
throw std::runtime_error(“Division by zero”);
}return a / b;
}int main() {
try {
int result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}return 0;
} -
try 关键字:
#include
#includeint main() {
try {
// 代码块,可能抛出异常
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}return 0;
} -
catch 关键字:
#include
#includeint main() {
try {
// 代码块,可能抛出异常
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}return 0;
} -
template 关键字:
#include
template
T sum(T a, T b) {
return a + b;
}int main() {
int result1 = sum(10, 20);
double result2 = sum(3.14, 2.71);std::cout << "Integer sum: " << result1 << std::endl;
std::cout << "Double sum: " << result2 << std::endl;return 0;
} -
typename 关键字:
#include
template
class MyClass {
public:
typename T::type value;
};int main() {
MyClass<std::pair<int, double>> obj;obj.value.first = 10;
obj.value.second = 3.14;std::cout << “Value: (” << obj.value.first << ", " << obj.value.second << “)” << std::endl;
return 0;
} -
operator 关键字:
#include
class MyClass {
public:
MyClass(int value) : value(value) {}MyClass operator+(const MyClass& other) const {
return MyClass(value + other.value);
}int getValue() const {
return value;
}private:
int value;
};int main() {
MyClass obj1(10);
MyClass obj2(20);MyClass obj3 = obj1 + obj2;
std::cout << "Sum: " << obj3.getValue() << std::endl;
return 0;
} -
this 关键字:
#include
class MyClass {
public:
MyClass(int value) : value(value) {}void printValue() {
std::cout << "Value: " << this->value << std::endl;
}private:
int value;
};int main() {
MyClass obj(10);
obj.printValue();return 0;
} -
new 关键字:
#include
class MyClass {
public:
MyClass() {
std::cout << “Constructor called” << std::endl;
}~MyClass() {
std::cout << “Destructor called” << std::endl;
}
};int main() {
MyClass* obj = new MyClass();delete obj; // 释放内存
return 0;
} -
delete 关键字:
#include
class MyClass {
public:
MyClass() {
std::cout << “Constructor called” << std::endl;
}~MyClass() {
std::cout << “Destructor called” << std::endl;
}
};int main() {
MyClass* obj = new MyClass();delete obj; // 调用析构函数
return 0;
} -
mutable 关键字:
#include
class MyClass {
public:
MyClass(int value) : value(value) {}void increment() const {
mutable int counter = 0;
counter++;
std::cout << "Counter: " << counter << std::endl;
}private:
int value;
};int main() {
MyClass obj(10);
obj.increment();return 0;
} -
inline 关键字:
#include
inline int add(int a, int b) {
return a + b;
}int main() {
int result = add(10, 20);std::cout << "Result: " << result << std::endl;
return 0;
} -
virtual 关键字:
#include
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};int main() {
Base* basePtr = new Derived();basePtr->print(); // 调用 Derived 类的 print() 方法
return 0;
} -
explicit 关键字:
#include
class MyClass {
public:
explicit MyClass(int
#include
#include
#include
#include
#include
#include
// 1. auto 关键字:自动类型推断
void autoExample() {
auto num = 10; // 自动推断为 int
auto str = “Hello”; // 自动推断为 const char*
std::vector vec = {1, 2, 3};
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
}
// 2. decltype 关键字:获取表达式类型
void decltypeExample() {
int a = 10;
decltype(a) b = 20; // b 的类型为 int
auto sum = [](int x, int y) -> decltype(x + y) { return x + y; };
std::cout << "a + b = " << sum(a, b) << std::endl;
}
// 3. constexpr 关键字:常量表达式
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
void constexprExample() {
constexpr int result = factorial(5); // 在编译时计算
int arr[result] = {}; // 使用常量表达式初始化数组大小
std::cout << "5! = " << result << std::endl;
}
// 4. lambda 表达式:匿名函数
void lambdaExample() {
std::vector v = {1, 5, 3, 2, 4};
std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; });
std::for_each(v.begin(), v.end(), [](int x) { std::cout << x << " "; });
std::cout << std::endl;
}
// 5. default/delete 关键字:控制默认函数生成
class MyClass {
public:
MyClass() = default; // 使用默认构造函数
MyClass(const MyClass&) = delete; // 禁止拷贝构造函数
MyClass& operator=(const MyClass&) = delete; // 禁止赋值运算符
};
void defaultDeleteExample() {
MyClass obj1;
// MyClass obj2 = obj1; // 错误:禁止拷贝构造
// obj1 = obj2; // 错误:禁止赋值运算符
}
// 6. nullptr 关键字:空指针
void nullptrExample() {
int* ptr = nullptr;
if (ptr == nullptr) {
std::cout << “Pointer is null” << std::endl;
}
}
// 7. [[deprecated]] 关键字:标记废弃
[[deprecated(“Use newFunction instead”)]]
void oldFunction() {
std::cout << “Old function called” << std::endl;
}
void newFunction() {
std::cout << “New function called” << std::endl;
}
void deprecatedExample() {
oldFunction(); // 编译器会给出警告
newFunction();
}
// 8. 数字分隔符:提高可读性
void numberSeparatorExample() {
long long bigNumber = 1’000’000’000;
std::cout << "Big number: " << bigNumber << std::endl;
}
// 9. override 关键字:重写虚函数
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void overrideExample() {
Derived derived;
derived.print();
}
Public继承:
公开继承(public inheritance)意味着基类的公有成员在派生类中保持为公有成员,保护成员在派生类中保持为保护成员,私有成员在派生类中不可直接访问。
派生类的对象可以被视为基类的对象,可以通过指向派生类对象的基类指针或引用来访问基类的成员。
Private继承:
私有继承(private inheritance)意味着基类的公有和保护成员在派生类中变为私有成员,无法直接访问。
派生类对象不能被视为基类对象,只能通过派生类的成员函数来访问基类的成员。
Protected继承:
保护继承(protected inheritance)意味着基类的公有和保护成员在派生类中变为保护成员,只能在派生类内部或其派生类中访问。
派生类对象不能被视为基类对象,只能通过派生类的成员函数来访问基类的成员。
// 10. final 关键字:阻止继承或重写
class BaseFinal {
public:
virtual void print() final {
std::cout << “BaseFinal class” << std::endl;
}
};
// class DerivedFinal : public BaseFinal { // 错误:无法继承
// void print() override; // 错误:无法重写
// };
void finalExample() {
BaseFinal baseFinal;
baseFinal.print();
}
// 11. static_cast 关键字:显式类型转换
void staticCastExample() {
double d = 3.14;
int i = static_cast(d);
std::cout << "Integer value: " << i << std::endl;
}
// 12. reinterpret_cast 关键字:重新解释数据类型
void reinterpretCastExample() {
int num = 10;
char* charPtr = reinterpret_cast<char*>(&num);
std::cout << "Character value: " << *charPtr << std::endl;
}
// 13. const_cast 关键字:修改 const 限定符
void constCastExample() {
const int num = 10;
int* ptr = const_cast<int*>(&num);
*ptr = 20;
std::cout << "Modified value: " << num << std::endl;
}
// 14. dynamic_cast 关键字:动态类型转换
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void dynamicCastExample() {
Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr != nullptr) {
derivedPtr->print();
} else {
std::cout << “Conversion failed” << std::endl;
}
delete basePtr;
}
// 15. typeid 关键字:获取类型信息
void typeidExample() {
int num = 10;
std::cout << "Type of num: " << typeid(num).name() << std::endl;
std::string str = “Hello”;
std::cout << "Type of str: " << typeid(str).name() << std::endl;
}
// 16. throw 关键字:抛出异常
void throwExample() {
try {
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// 17. try 关键字:异常处理块
void tryExample() {
try {
// 可能抛出异常的代码
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// 18. catch 关键字:捕获异常
void catchExample() {
try {
// 可能抛出异常的代码
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// 19. template 关键字:模板
template
T sum(T a, T b) {
return a + b;
}
void templateExample() {
int result1 = sum(10, 20);
double result2 = sum(3.14, 2.71);
std::cout << "Integer sum: " << result1 << std::endl;
std::cout << "Double sum: " << result2 << std::endl;
}
// 20. typename 关键字:在模板中使用依赖类型
template
class MyClass {
public:
typename T::type value;
};
void typenameExample() {
MyClass<std::pair<int, double>> obj;
obj.value.first = 10;
obj.value.second = 3.14;
std::cout << “Value: (” << obj.value.first << ", " << obj.value.second << “)” << std::endl;
}
// 21. operator 关键字:运算符重载
class MyClass {
public:
MyClass(int value) : value(value) {}
MyClass operator+(const MyClass& other) const {
return MyClass(value + other.value);
}
int getValue() const {
return value;
}
private:
int value;
};
void operatorExample() {
MyClass obj1(10);
MyClass obj2(20);
MyClass obj3 = obj1 + obj2;
std::cout << "Sum: " << obj3.getValue() << std::endl;
}
// 22. this 关键字:指向当前对象的指针
class MyClass {
public:
MyClass(int value) : value(value) {}
void printValue() {
std::cout << "Value: " << this->value << std::endl;
}
private:
int value;
};
void thisExample() {
MyClass obj(10);
obj.printValue();
}
// 23. new 关键字:动态内存分配
void newExample() {
int* ptr = new int(10);
std::cout << "Value: " << *ptr << std::endl;
delete ptr;
}
// 24. delete 关键字:释放动态内存
void deleteExample() {
int* ptr = new int(10);
delete ptr;
}
// 25. mutable 关键字:允许在 const 成员函数中修改数据成员
class MyClass {
public:
MyClass(int value) : value(value) {}
void increment() const {
mutable int counter = 0;
counter++;
std::cout << "Counter: " << counter << std::endl;
}
private:
int value;
};
void mutableExample() {
MyClass obj(10);
obj.increment();
}
// 26. inline 关键字:建议编译器将函数内联
inline int add(int a, int b) {
return a + b;
}
void inlineExample() {
int result = add(10, 20);
std::cout << "Result: " << result << std::endl;
}
// 27. virtual 关键字:虚函数
class Base {
public:
virtual void print() {
std::cout << “Base class” << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << “Derived class” << std::endl;
}
};
void virtualExample() {
Base* basePtr = new Derived();
basePtr->print(); // 调用 Derived 类的 print() 方法
delete basePtr;
}
// 28. explicit 关键字:阻止隐式类型转换
class MyClass {
public:
explicit MyClass(int value) : value(value) {}
int getValue() const {
return value;
}
private:
int value;
};
void explicitExample() {
// MyClass obj = 10; // 错误:禁止隐式转换
MyClass obj(10); // 正确:显式调用构造函数
std::cout << "Value: " << obj.getValue() << std::endl;
}
// 29. friend 关键字:友元函数
class MyClass {
public:
friend void printValue(const MyClass& obj);
MyClass(int value) : value(value) {}
private:
int value;
};
void printValue(const MyClass& obj) {
std::cout << "Value: " << obj.value << std::endl;
}
void friendExample() {
MyClass obj(10);
printValue(obj);
}
// 30. sizeof 关键字:获取数据类型的大小
void sizeofExample() {
int num = 10;
std::cout << "Size of int: " << sizeof(num) << std::endl;
}
// 31. alignof 关键字:获取数据类型的对齐方式
void alignofExample() {
int num = 10;
std::cout << "Alignment of int: " << alignof(num) << std::endl;
}
// 32. noexcept 关键字:声明函数不会抛出异常
int add(int a, int b) noexcept {
return a + b;
}
void noexceptExample() {
int result = add(10, 20);
std::cout << "Result: " << result << std::endl;
}
int main() {
autoExample();
decltypeExample();
constexprExample();
lambdaExample();
defaultDeleteExample();
nullptrExample();
deprecatedExample();
numberSeparatorExample();
overrideExample();
finalExample();
staticCastExample();
reinterpretCastExample();
constCastExample();
dynamicCastExample();
typeidExample();
throwExample();
tryExample();
catchExample();
templateExample();
typenameExample();
operatorExample();
thisExample();
newExample();
deleteExample();
mutableExample();
inlineExample();
virtualExample();
explicitExample();
friendExample();
sizeofExample();
alignofExample();
noexceptExample();
return 0;
}
好的,很高兴继续演示 C++ 关键字。以下是一些其他重要的关键字,以及它们的用法和示例:
1. mutable
- 用途:用于声明一个类成员变量,即使该成员变量所在的类对象是常量,也可以被修改。
- 示例:
class MyClass {
public:
mutable int count; // 即使 MyClass 对象是常量,count 也可以被修改
void increment() {
count++;
}
};
int main() {
const MyClass myObject; // myObject 是常量对象
myObject.increment(); // 仍然可以调用 increment() 函数,修改 count
return 0;
}
2. explicit
- 用途:用于声明一个构造函数,防止它被用于隐式类型转换。
- 示例:
class MyInt {
public:
explicit MyInt(int value) : value(value) {}
int value;
};
int main() {
MyInt myInt1(10); // 正确的初始化方式
// MyInt myInt2 = 10; // 错误,因为 MyInt 的构造函数被声明为 explicit
return 0;
}
3. friend
- 用途:用于声明一个函数或类为另一个类的友元,允许友元访问该类的私有成员。
- 示例:
class MyClass {
private:
int data;
public:
friend void printData(MyClass obj); // 声明 printData 函数为 MyClass 的友元
};
void printData(MyClass obj) {
std::cout << "Data: " << obj.data << std::endl; // 可以访问 MyClass 的私有成员 data
}
int main() {
MyClass myObject;
myObject.data = 10; // 错误,无法直接访问私有成员
printData(myObject); // 可以通过友元函数访问私有成员
return 0;
}
4. typeid
- 用途:用于获取一个对象的类型信息。
- 示例:
#include <typeinfo>
class MyClass {};
int main() {
MyClass myObject;
std::cout << "Type of myObject: " << typeid(myObject).name() << std::endl;
return 0;
}
5. dynamic_cast
- 用途:用于在运行时进行类型转换,如果转换失败,则返回 nullptr。
- 示例:
#include <iostream>
class Base {
public:
virtual void print() {
std::cout << "Base class" << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << "Derived class" << std::endl;
}
};
int main() {
Base *basePtr = new Derived();
Derived *derivedPtr = dynamic_cast<Derived*>(basePtr); // 转换成功
if (derivedPtr != nullptr) {
derivedPtr->print(); // 调用 Derived 类中的 print() 函数
}
return 0;
}
6. reinterpret_cast
- 用途:用于将一个指针转换为另一个类型的指针,不进行任何类型检查。
- 示例:
int value = 10;
int *intPtr = &value;
char *charPtr = reinterpret_cast<char*>(intPtr); // 将 int 指针转换为 char 指针
7. const_cast
- 用途:用于移除一个对象的常量性。
- 示例:
const int value = 10;
int *intPtr = const_cast<int*>(&value); // 移除 value 的常量性
*intPtr = 20; // 可以修改 value 的值
8. static_cast
- 用途:用于在编译时进行类型转换,可以用于将一个类型转换为另一个类型,但需要确保转换是安全的。
- 示例:
double d = 3.14;
int i = static_cast<int>(d); // 将 double 转换为 int
9. sizeof
- 用途:用于获取一个类型或变量的大小(以字节为单位)。
- 示例:
int value = 10;
std::cout << "Size of int: " << sizeof(int) << std::endl;
std::cout << "Size of value: " << sizeof(value) << std::endl;
10. alignof
- 用途:用于获取一个类型的对齐方式。
- 示例:
std::cout << "Alignment of int: " << alignof(int) << std::endl;
11. noexcept
- 用途:用于声明一个函数是否可能抛出异常。
- 示例:
int add(int a, int b) noexcept { // 声明 add 函数不会抛出异常
return a + b;
}
12. constexpr
- 用途:用于声明一个常量表达式,可以在编译时计算。
- 示例:
constexpr int square(int x) {
return x * x;
}
int main() {
constexpr int result = square(5); // 在编译时计算 result 的值
std::cout << "Result: " << result << std::endl;
return 0;
}
13. decltype
- 用途:用于获取一个表达式的类型。
- 示例:
int value = 10;
decltype(value) anotherValue = 20; // anotherValue 的类型为 int
14. nullptr
- 用途:用于表示空指针。
- 示例:
int *ptr = nullptr; // 初始化 ptr 为空指针
15. using
- 用途:用于创建别名或将命名空间中的成员引入当前作用域。
- 示例:
using MyInt = int; // 创建 MyInt 类型的别名
using namespace std; // 将 std 命名空间中的成员引入当前作用域
16. auto
- 用途:用于自动推断变量的类型。
- 示例:
auto value = 10; // value 的类型为 int
17. template
- 用途:用于创建泛型函数或类。
- 示例:
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int result1 = add(10, 20); // 调用 add 函数,类型为 int
double result2 = add(3.14, 2.71); // 调用 add 函数,类型为 double
return 0;
}
18. typename
- 用途:用于在模板中指定一个类型。
- 示例:
template <typename T>
class MyClass {
public:
typename T::value_type value; // 使用 typename 指定 T::value_type 为一个类型
};
19. operator
- 用途:用于声明运算符重载函数。
- 示例:
class MyInt {
public:
int value;
MyInt(int value) : value(value) {}
MyInt operator+(const MyInt &other) const {
return MyInt(value + other.value);
}
};
int main() {
MyInt myInt1(10);
MyInt myInt2(20);
MyInt myInt3 = myInt1 + myInt2; // 使用 + 运算符重载函数
std::cout << "myInt3.value: " << myInt3.value << std::endl;
return 0;
}
20. namespace
- 用途:用于定义命名空间,用于组织代码并避免命名冲突。
- 示例:
namespace MyNamespace {
int value = 10;
}
int main() {
std::cout << "MyNamespace::value: " << MyNamespace::value << std::endl;
return 0;
}
21. volatile
- 用途:用于声明一个变量,即使该变量的值没有被显式修改,编译器也不应该对其进行优化。
- 示例:
volatile int value = 0; // value 可能会被外部因素修改,例如硬件中断
int main() {
while (true) {
// ...
value++; // 每次循环都读取 value 的值,即使它没有被修改
// ...
}
return 0;
}
22. register
- 用途:用于建议编译器将一个变量存储在寄存器中,以提高访问速度。
- 示例:
register int i; // 建议将 i 存储在寄存器中
for (i = 0; i < 10; i++) {
// ...
}
23. extern
- 用途:用于声明一个变量或函数,其定义在其他文件中。
- 示例:
// 在 file1.cpp 中
int value = 10;
// 在 file2.cpp 中
extern int value; // 声明 value 在其他文件中定义
24. inline
- 用途:用于建议编译器将一个函数内联,以提高执行速度。
- 示例:
inline int add(int a, int b) {
return a + b;
}
25. virtual
- 用途:用于声明一个虚函数,允许在派生类中重写该函数。
- 示例:
class Base {
public:
virtual void print() {
std::cout << "Base class" << std::endl;
}
};
class Derived : public Base {
public:
void print() override { // 重写 Base 类中的 print 函数
std::cout << "Derived class" << std::endl;
}
};
26. override
- 用途:用于声明一个函数重写了基类中的虚函数。
- 示例:
class Base {
public:
virtual void print() {
std::cout << "Base class" << std::endl;
}
};
class Derived : public Base {
public:
void print() override { // 重写 Base 类中的 print 函数
std::cout << "Derived class" << std::endl;
}
};
27. final
- 用途:用于声明一个类或函数不能被继承或重写。
- 示例:
class Base final { // Base 类不能被继承
// ...
};
class Derived : public Base { // 错误,Base 类不能被继承
// ...
};
class Base {
public:
virtual void print() final { // print 函数不能被重写
std::cout << "Base class" << std::endl;
}
};
class Derived : public Base {
public:
void print() override { // 错误,print 函数不能被重写
std::cout << "Derived class" << std::endl;
}
};
28. delete
- 用途:用于删除一个对象或释放内存。
- 示例:
int *ptr = new int(10);
delete ptr; // 释放 ptr 指向的内存
29. new
- 用途:用于动态分配内存。
- 示例:
int *ptr = new int(10); // 分配一个 int 类型的大小,并初始化为 10
30. this
- 用途:用于指向当前对象的指针。
- 示例:
class MyClass {
public:
int value;
void print() {
std::cout << "Value: " << this->value << std::endl; // 使用 this 指针访问成员变量
}
};
31. operator new
- 用途:用于重载
new
运算符,自定义内存分配方式。 - 示例:
void* operator new(size_t size) {
// 自定义内存分配逻辑
return malloc(size);
}
int main() {
int *ptr = new int(10); // 使用自定义的 new 运算符分配内存
return 0;
}
32. operator delete
- 用途:用于重载
delete
运算符,自定义内存释放方式。 - 示例:
void operator delete(void *ptr) {
// 自定义内存释放逻辑
free(ptr);
}
int main() {
int *ptr = new int(10);
delete ptr; // 使用自定义的 delete 运算符释放内存
return 0;
}
33. throw
- 用途:用于抛出异常。
- 示例:
#include <iostream>
int main() {
try {
throw std::runtime_error("Error occurred!");
} catch (const std::exception &e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
34. try
- 用途:用于捕获异常。
- 示例:
#include <iostream>
int main() {
try {
throw std::runtime_error("Error occurred!");
} catch (const std::exception &e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
35. catch
- 用途:用于处理捕获的异常。
- 示例:
#include <iostream>
int main() {
try {
throw std::runtime_error("Error occurred!");
} catch (const std::exception &e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
36. goto
- 用途:用于无条件跳转到程序中的另一个位置。
- 示例:
int main() {
int i = 0;
loop:
if (i < 10) {
std::cout << i << std::endl;
i++;
goto loop;
}
return 0;
}
37. asm
- 用途:用于嵌入汇编代码。
- 示例:
int main() {
asm("mov eax, 1"); // 嵌入汇编代码
return 0;
}
38. __attribute__
- 用途:用于添加函数或变量的属性。
- 示例:
int myFunction() __attribute__((noreturn)); // 声明 myFunction 函数不会返回
39. __func__
- 用途:用于获取当前函数的名称。
- 示例:
void myFunction() {
std::cout << "Function name: " << __func__ << std::endl;
}
40. __LINE__
- 用途:用于获取当前代码行的行号。
- 示例:
void myFunction() {
std::cout << "Line number: " << __LINE__ << std::endl;
}
41. __FILE__
- 用途:用于获取当前源文件的名称。
- 示例:
void myFunction() {
std::cout << "File name: " << __FILE__ << std::endl;
}
42. __DATE__
- 用途:用于获取编译日期。
- 示例:
int main() {
std::cout << "Compilation date: " << __DATE__ << std::endl;
return 0;
}
43. __TIME__
- 用途:用于获取编译时间。
- 示例:
int main() {
std::cout << "Compilation time: " << __TIME__ << std::endl;
return 0;
}
44. __cplusplus
- 用途:用于检查当前编译器是否支持 C++。
- 示例:
#ifdef __cplusplus
std::cout << "C++ is supported" << std::endl;
#endif
45. __VA_ARGS__
- 用途:用于在宏定义中访问可变参数。
46. sizeof
运算符
- 用途:用于获取数据类型或变量的大小(以字节为单位)。
- 示例:
#include <iostream>
int main() {
int num = 10;
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
std::cout << "Size of num: " << sizeof(num) << " bytes" << std::endl;
return 0;
}
47. alignof
运算符
- 用途:用于获取数据类型的对齐方式。
- 示例:
#include <iostream>
int main() {
int num = 10;
std::cout << "Alignment of int: " << alignof(int) << std::endl;
return 0;
}
在C++中,数据类型的对齐方式是编译器根据平台架构和优化考虑来决定如何在内存中排列数据。数据类型的对齐方式可以影响内存访问的效率和数据存储的紧凑性。以下是一些常见的数据类型对齐规则:
-
默认对齐:
- 在C++中,数据类型的默认对齐方式通常是按照其自身大小进行对齐。例如,
char
通常对齐到1字节,int
对齐到4字节(32位系统)或8字节(64位系统)等。
- 在C++中,数据类型的默认对齐方式通常是按照其自身大小进行对齐。例如,
-
结构体对齐:
- 结构体的对齐方式是按照结构体中最大成员的大小进行对齐。这样做是为了保证结构体的每个成员都能够被正确对齐,以提高访问效率。
- 结构体的大小通常是其成员大小的倍数,但也受到编译器的优化和对齐规则的影响。
-
指定对齐方式:
- 可以使用
#pragma pack(n)
指令或__attribute__((packed))
属性来指定结构体的对齐方式,将其设置为n字节对齐。这样可以控制结构体在内存中的紧凑性,但可能会影响访问效率。
- 可以使用
-
对齐补齐:
- 为了满足对齐要求,编译器可能会在结构体成员之间插入填充字节(padding),使得结构体的起始地址和每个成员的地址都符合对齐要求。
- 对齐补齐可以确保数据的访问效率,但可能会增加内存的占用。
-
数据类型对齐的优化:
- 在一些特定情况下,编译器可能会根据平台和编译选项进行数据类型对齐的优化,以提高程序的性能和效率。
假设有以下结构体定义:
#include <iostream>
struct MyStruct {
char a;
int b;
double c;
};
int main() {
std::cout << "Size of MyStruct: " << sizeof(MyStruct) << " bytes" << std::endl;
return 0;
}
在这个示例中,MyStruct
结构体包含一个 char
类型的成员 a
,一个 int
类型的成员 b
,和一个 double
类型的成员 c
。
当运行这段代码时,会得到结构体 MyStruct
的大小。这个大小取决于结构体成员的大小和对齐方式。可以通过以下方式观察结构体成员在内存中的布局情况:
char a
:char
类型通常占用1字节。int b
:在大多数系统上,int
类型通常占用4字节。double c
:double
类型通常占用8字节。
根据默认对齐规则,结构体的对齐方式通常是按照最大成员的大小进行对齐。在这个例子中,double
类型的 c
成员是最大的,因此结构体 MyStruct
的大小可能会是 1(char) + 3(padding) + 4(int) + 8(double) = 16 字节。
好处:
访问效率提高:数据类型对齐可以提高内存访问的效率。当数据按照合适的边界对齐时,处理器可以更快地访问内存中的数据,因为它们可以直接从内存中读取对齐的数据,而无需额外的处理。
硬件要求:许多计算机体系结构要求数据按照特定的边界对齐,否则可能会导致性能下降甚至程序崩溃。
平台兼容性:正确对齐数据类型可以增加代码在不同平台上的可移植性,避免因为对齐问题导致程序在不同平台上表现不一致的情况。
内存空间利用:对齐数据类型可以减少内存碎片,提高内存空间的利用率。
坏处:
内存浪费:对齐数据类型可能会导致内存浪费。为了满足对齐要求,编译器可能会在数据类型之间插入填充字节,增加结构体或类的大小。
结构体大小增加:由于对齐要求,结构体或类的大小可能会比成员变量的总和更大,导致额外的内存消耗。
复杂性:手动控制数据类型的对齐可能会增加代码的复杂性,尤其是在需要处理不同平台的情况下。
数据类型对齐在提高访问效率和硬件兼容性方面带来了明显的好处,但在内存利用和复杂性方面可能会带来一些不利影响。通常情况下,编译器会根据平台架构和优化考虑自动处理数据类型的对齐,以平衡性能和内存利用率。
48. noexcept
关键字
- 用途:用于声明一个函数不会抛出异常。
- 示例:
#include <iostream>
int divide(int a, int b) noexcept {
if (b == 0) {
throw std::runtime_error("Division by zero");
}
return a / b;
}
int main() {
try {
int result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
49. throw
关键字
- 用途:用于抛出异常。
- 示例:
#include <iostream>
#include <stdexcept>
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("Division by zero");
}
return a / b;
}
int main() {
try {
int result = divide(10, 0);
std::cout << "Result: " << result << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
当然,这里是关于这些C++关键字的详细讲解:
27. consteval
consteval
关键字用来声明一个立即函数,表示这个函数在编译时就必须进行常量求值。这样确保函数在编译期就返回结果,不能在运行时调用。示例如下:
consteval int square(int n) {
return n * n;
}
int main() {
constexpr int result = square(5); // 正常,编译期计算
// int result2 = square(5); // 错误,不能在运行时调用
return 0;
}
29. constinit
constinit
关键字确保变量在程序启动时被静态初始化(即常量初始化)。如果没有这一关键字,可能会导致初始化顺序的问题。示例如下:
constinit int global_var = 42; // 确保在程序启动时静态初始化
int main() {
return 0;
}
30. const_cast
const_cast
用于移除变量的const
属性,或添加/移除volatile
属性。它主要用于指针或引用的类型转换。示例如下:
void func(const int* p) {
int* modifiable = const_cast<int*>(p);
*modifiable = 10; // 允许修改值
}
int main() {
const int a = 5;
func(&a);
return 0;
}
33. default
default
关键字主要用于在类的定义中显式声明默认构造函数、析构函数、拷贝构造函数、移动构造函数和赋值运算符。示例如下:
class MyClass {
public:
MyClass() = default; // 使用默认构造函数
~MyClass() = default; // 使用默认析构函数
};
37. dynamic_cast
dynamic_cast
用于在运行时进行安全的多态类型转换。它通常用于将基类指针或引用转换为派生类指针或引用。示例如下:
class Base { virtual void func() {} };
class Derived : public Base { void func() override {} };
int main() {
Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b); // 安全的转换
return 0;
}
40. explicit
explicit
关键字用于修饰构造函数,防止它被隐式调用,从而避免隐式转换。示例如下:
class MyClass {
public:
explicit MyClass(int x) {} // 防止隐式转换
};
int main() {
MyClass obj1(10); // 正常
// MyClass obj2 = 10; // 错误,隐式转换被禁止
return 0;
}
41. export
export
关键字用于模板的导出,使模板定义与声明分离。但由于支持有限,这个关键字在实际中很少使用,并且在C++20中被移除了。
52. mutable
mutable
关键字用于允许在const
成员函数中修改某些数据成员。示例如下:
class MyClass {
public:
mutable int x;
MyClass() : x(0) {}
void modify() const { x = 10; } // 允许修改x
};
53. namespace
namespace
用于定义命名空间,以避免名字冲突。示例如下:
namespace MyNamespace {
int value = 42;
}
int main() {
int value = 0;
value = MyNamespace::value; // 使用命名空间中的value
return 0;
}
59. operator
operator
关键字用于重载运算符。示例如下:
class MyClass {
public:
int value;
MyClass(int v) : value(v) {}
MyClass operator+(const MyClass& other) {
return MyClass(value + other.value);
}
};
int main() {
MyClass a(5), b(10);
MyClass c = a + b; // 使用重载的+运算符
return 0;
}
63. protected
protected
访问修饰符允许派生类访问基类的成员,但外部代码不能访问。示例如下:
class Base {
protected:
int value;
};
class Derived : public Base {
public:
void setValue(int v) { value = v; }
};
int main() {
Derived d;
d.setValue(10); // 正常
// d.value = 10; // 错误,不能直接访问protected成员
return 0;
}
66. reinterpret_cast
reinterpret_cast
用于进行类型的低级别转换,一般用于不同指针类型之间的转换。它不会进行任何检查,所以需要谨慎使用。示例如下:
int main() {
int a = 65;
char* p = reinterpret_cast<char*>(&a); // 将int指针转换为char指针
std::cout << *p << std::endl; // 输出'A',ASCII码为65
return 0;
}
67. requires
requires
关键字用于定义C++20中的概念,来约束模板参数。它用于检查模板参数是否符合某些条件。示例如下:
template<typename T>
concept Incrementable = requires(T x) {
x++;
};
template<Incrementable T>
void increment(T& x) {
++x;
}
int main() {
int a = 5;
increment(a); // 正常
return 0;
}
70. signed
signed
关键字用于声明整数类型是有符号的。它是默认的,因此一般不需要显式使用。示例如下:
signed int a = -10; // 有符号整数
unsigned int b = 10; // 无符号整数
int main() {
std::cout << a << " " << b << std::endl; // 输出-10 10
return 0;
}
72. static
static
关键字有多种用途,包括:
- 静态变量:在函数内部,静态变量在函数调用之间保留其值。
- 静态成员:在类中,静态成员属于类而不是某个对象。
- 静态函数:在类中,静态函数可以不依赖于对象实例调用。
示例如下:
void func() {
static int count = 0; // 静态变量
count++;
std::cout << count << std::endl;
}
class MyClass {
public:
static int static_value; // 静态成员变量
static void static_func() { // 静态成员函数
std::cout << "Static function" << std::endl;
}
};
int MyClass::static_value = 0;
int main() {
func(); // 输出1
func(); // 输出2
MyClass::static_value = 10;
MyClass::static_func(); // 输出"Static function"
return 0;
}
73. static_assert
static_assert
用于在编译时进行断言,如果条件不满足,编译器会生成错误。示例如下:
static_assert(sizeof(int) == 4, "int类型大小必须是4字节");
int main() {
return 0;
}
74. static_cast
static_cast
用于进行显式类型转换,适用于常规类型转换,包括基本数据类型之间的转换和类层次结构中的向上转换和向下转换。示例如下:
int main() {
double d = 3.14;
int a = static_cast<int>(d); // 将double转换为int
std::cout << a << std::endl; // 输出3
return 0;
}
77. synchronized
synchronized
关键字并不是标准C++的一部分,而是Java中的关键字。在C++中,通常使用std::mutex
和其他同步机制来实现线程同步。示例如下:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::lock_guard<std::mutex> lock(mtx); // 自动管理锁的获取与释放
std::cout << "Thread ID: " << id << std::endl;
}
int main() {
std::thread t1(print_thread_id, 1);
std::thread t2(print_thread_id, 2);
t1.join();
t2.join();
return 0;
}
78. template
template
关键字用于定义模板,支持泛型编程,使得函数和类可以处理任意类型。示例如下:
template<typename T>
T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(3, 4) << std::endl; // 输出7
std::cout << add(3.5, 4.5) << std::endl; // 输出8.0
return 0;
}
80. thread_local
thread_local
关键字用于声明线程局部存储的变量,即每个线程都有其独立的变量副本。示例如下:
#include <iostream>
#include <thread>
thread_local int value = 0;
void print_value() {
value++;
std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << value << std::endl;
}
int main() {
std::thread t1(print_value);
std::thread t2(print_value);
t1.join();
t2.join();
return 0;
}
84. typedef
typedef
用于为现有类型定义新的类型名。它可以使代码更加简洁和易读。示例如下:
typedef unsigned long ulong;
int main() {
ulong a = 100;
std::cout << a << std::endl; // 输出100
return 0;
}
85. typeid
typeid
用于获取类型信息,通常与RTTI(运行时类型信息)一起使用。示例如下:
#include <iostream>
#include <typeinfo>
int main() {
int a = 10;
std::cout << "Type of a: " << typeid(a).name() << std::endl; // 输出int类型的信息
return 0;
}
86. typename
typename
关键字用于模板中声明类型名称,通常用于表示依赖于模板参数的类型。示例如下:
template<typename T>
class MyClass {
public:
typename T::value_type value; // 使用typename表示依赖类型
};
int main() {
return 0;
}
C++多线程模型一般可以使用线程,也可以使用协程,具体选择取决于需求和应用场景。
线程模型
C++11引入了标准线程库,通过std::thread
类可以轻松创建和管理线程。以下是一个简单的多线程示例:
#include <iostream>
#include <thread>
void printHello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(printHello);
t.join(); // 等待线程结束
std::cout << "Hello from main!" << std::endl;
return 0;
}
协程模型
C++20引入了协程,协程是一种更加轻量级的并发方式。协程在执行期间可以被暂停和恢复,适用于处理异步任务。以下是一个简单的协程示例:
#include <iostream>
#include <coroutine>
struct Task {
struct promise_type {
Task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
Task example() {
std::cout << "Start of coroutine" << std::endl;
co_await std::suspend_always{};
std::cout << "End of coroutine" << std::endl;
}
int main() {
example();
return 0;
}
选择线程还是协程
- 线程:适用于CPU密集型任务、需要并行执行的独立任务。线程之间可以通过锁和条件变量进行同步。
- 协程:适用于I/O密集型任务、需要处理大量异步操作的情况。协程的开销更低,可以提高资源利用率和响应速度。
选择线程还是协程取决于具体的应用场景和需求。如果需要处理大量并发I/O操作,可以优先考虑协程;如果任务需要并行处理且独立运行,则可以选择线程。
#include <iostream>
// 定义一个简单的模板类
template <typename T>
class Pair {
private:
T first;
T second;
public:
Pair(T f, T s) : first(f), second(s) {}
void display() {
std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
}
};
// 定义一个简单的模板函数
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
// 实例化模板类 Pair,并展示其功能
Pair<int> intPair(10, 20);
intPair.display();
Pair<double> doublePair(3.14, 2.71);
doublePair.display();
// 调用模板函数 add,并展示其功能
int sumInt = add(5, 10);
std::cout << "Sum of integers: " << sumInt << std::endl;
double sumDouble = add(3.14, 2.71);
std::cout << "Sum of doubles: " << sumDouble << std::endl;
return 0;
}
在这个示例中,定义了一个模板类 Pair
,它可以存储一对相同类型的值,并提供了一个 display
方法来显示这对值。还定义了一个模板函数 add
,它可以对两个相同类型的值进行加法运算。
在 main
函数中,展示了如何实例化模板类 Pair
以处理不同类型的值,并调用模板函数 add
来处理不同类型的加法操作。
以下是一个简单的示例,演示了如何在 C++ 中使用线程和互斥锁(mutex)来实现多线程并发操作:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 定义一个互斥锁
void printNumbers(int id) {
mtx.lock(); // 加锁
for (int i = 1; i <= 5; ++i) {
std::cout << "Thread " << id << ": " << i << std::endl;
}
mtx.unlock(); // 解锁
}
int main() {
// 创建两个线程并启动
std::thread t1(printNumbers, 1);
std::thread t2(printNumbers, 2);
// 等待两个线程执行完毕
t1.join();
t2.join();
return 0;
}
在这个示例中,首先包含了 <thread>
和 <mutex>
头文件,分别用于多线程和互斥锁的操作。
在 main
函数中,创建了两个线程 t1
和 t2
,它们都调用 printNumbers
函数,并传入不同的线程 ID。在 printNumbers
函数中,使用 std::mutex
定义了一个互斥锁 mtx
,并在需要保护临界区的代码段前后使用 mtx.lock()
和 mtx.unlock()
来实现对临界区的互斥访问。
当一个线程进入临界区并获得锁时,另一个线程会被阻塞,直到第一个线程释放锁。这样可以确保多个线程不会同时访问共享资源,避免数据竞争和不确定行为。
在本示例中,两个线程分别打印数字 1 到 5,由于使用了互斥锁,打印操作是依次进行的,而不会交叉进行。
在C++中,实现并发编程和多线程(也称携程)的常用方法包括使用标准库中的<thread>
和<future>
头文件。以下是详细的演示和讲解。
基本线程示例
在C++11中,可以使用std::thread
来创建和管理线程。下面是一个简单的例子,演示如何创建和运行线程。
#include <iostream>
#include <thread>
// 线程函数
void hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
// 创建一个线程并执行函数hello
std::thread t(hello);
// 等待线程t完成
t.join();
return 0;
}
在这个例子中,创建了一个新的线程t
,它运行函数hello
,并在主线程中等待线程t
完成。
带参数的线程函数
线程函数可以接受参数。以下是一个传递参数给线程函数的例子:
#include <iostream>
#include <thread>
// 带参数的线程函数
void print_number(int x) {
std::cout << "Thread printing: " << x << std::endl;
}
int main() {
int number = 42;
// 创建一个线程并传递参数
std::thread t(print_number, number);
// 等待线程t完成
t.join();
return 0;
}
在这个例子中,线程函数print_number
接受一个整数参数,并打印它的值。
使用std::mutex
进行线程同步
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 全局互斥锁
void print_with_lock(int x) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
std::cout << "Thread printing with lock: " << x << std::endl;
}
int main() {
std::thread t1(print_with_lock, 1);
std::thread t2(print_with_lock, 2);
t1.join();
t2.join();
return 0;
}
在这个例子中,std::lock_guard
用于管理互斥锁的生命周期,确保在访问共享资源时只有一个线程可以执行。
使用std::future
和std::promise
C++11提供了std::future
和std::promise
来实现线程之间的通信。std::promise
用于在一个线程中设置值,std::future
用于在另一个线程中获取值。以下是一个例子:
#include <iostream>
#include <thread>
#include <future>
// 计算平方的函数
void compute_square(std::promise<int>& p, int x) {
int result = x * x;
p.set_value(result); // 设置promise的值
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(compute_square, std::ref(prom), 4);
int result = fut.get(); // 获取计算结果
std::cout << "The square is: " << result << std::endl;
t.join();
return 0;
}
在这个例子中,一个线程计算一个数的平方并将结果通过std::promise
传递给主线程,主线程通过std::future
获取结果。
使用std::async
进行异步操作
std::async
提供了一种简单的方法来启动异步任务并获取其结果。以下是一个例子:
#include <iostream>
#include <future>
// 计算平方的函数
int compute_square(int x) {
return x * x;
}
int main() {
// 异步调用compute_square
std::future<int> fut = std::async(std::launch::async, compute_square, 4);
int result = fut.get(); // 获取计算结果
std::cout << "The square is: " << result << std::endl;
return 0;
}
在这个例子中,std::async
用于启动一个异步任务,并返回一个std::future
对象,主线程可以通过该对象获取异步任务的结果。
使用std::condition_variable
进行线程间的等待通知
std::condition_variable
用于实现复杂的线程间同步机制。以下是一个生产者-消费者模型的例子:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> q;
void producer() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
q.push(i);
std::cout << "Produced: " << i << std::endl;
cv.notify_one();
}
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !q.empty(); });
int item = q.front();
q.pop();
std::cout << "Consumed: " << item << std::endl;
if (item == 9) break;
}
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
在这个例子中,生产者线程向队列中添加数据,并通知消费者线程。消费者线程等待通知并处理队列中的数据。
在C++中,有多种类型的锁可以用于同步多线程访问共享资源。这些锁包括std::mutex
、std::recursive_mutex
、std::timed_mutex
、std::recursive_timed_mutex
、std::shared_mutex
(C++17引入)等。下面将详细演示这些锁的使用。
std::mutex
std::mutex
是最基本的互斥锁,用于保护共享资源以避免数据竞态。
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_number(int x) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
std::cout << "Thread printing: " << x << std::endl;
}
int main() {
std::thread t1(print_number, 1);
std::thread t2(print_number, 2);
t1.join();
t2.join();
return 0;
}
std::recursive_mutex
std::recursive_mutex
允许同一个线程多次锁定互斥锁。
#include <iostream>
#include <thread>
#include <mutex>
std::recursive_mutex rec_mtx;
void recursive_function(int depth) {
if (depth <= 0) return;
rec_mtx.lock();
std::cout << "Depth: " << depth << std::endl;
recursive_function(depth - 1);
rec_mtx.unlock();
}
int main() {
std::thread t1(recursive_function, 5);
t1.join();
return 0;
}
std::timed_mutex
std::timed_mutex
提供了尝试在一段时间内锁定互斥锁的功能。
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::timed_mutex t_mtx;
void try_lock_for_seconds(int id, int seconds) {
if (t_mtx.try_lock_for(std::chrono::seconds(seconds))) {
std::cout << "Thread " << id << " acquired the lock." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
t_mtx.unlock();
} else {
std::cout << "Thread " << id << " failed to acquire the lock." << std::endl;
}
}
int main() {
std::thread t1(try_lock_for_seconds, 1, 1);
std::thread t2(try_lock_for_seconds, 2, 2);
t1.join();
t2.join();
return 0;
}
std::recursive_timed_mutex
std::recursive_timed_mutex
结合了std::recursive_mutex
和std::timed_mutex
的功能,允许同一个线程多次锁定互斥锁,并提供尝试在一段时间内锁定的功能。
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::recursive_timed_mutex rec_t_mtx;
void recursive_try_lock(int depth, int id) {
if (depth <= 0) return;
if (rec_t_mtx.try_lock_for(std::chrono::seconds(1))) {
std::cout << "Thread " << id << " acquired lock at depth " << depth << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
recursive_try_lock(depth - 1, id);
rec_t_mtx.unlock();
} else {
std::cout << "Thread " << id << " failed to acquire lock at depth " << depth << std::endl;
}
}
int main() {
std::thread t1(recursive_try_lock, 3, 1);
std::thread t2(recursive_try_lock, 3, 2);
t1.join();
t2.join();
return 0;
}
std::shared_mutex (C++17)
std::shared_mutex
允许多个线程同时读取共享资源,但只有一个线程可以写入。这种锁在读多写少的场景中非常有用。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
std::shared_mutex sh_mtx;
std::vector<int> shared_data;
void reader(int id) {
std::shared_lock<std::shared_mutex> lock(sh_mtx); // 共享锁
std::cout << "Reader " << id << " is reading data: for (int num : shared_data) {
std::cout << num << " ";
}
std::cout << std::endl;
}
void writer(int id, int value) {
std::unique_lock<std::shared_mutex> lock(sh_mtx); // 独占锁
shared_data.push_back(value);
std::cout << "Writer " << id << " added value: " << value << std::endl;
}
int main() {
std::thread t1(reader, 1);
std::thread t2(writer, 2, 10);
std::thread t3(reader, 3);
t1.join();
t2.join();
t3.join();
return 0;
}
当一个线程申请使用写锁(独占锁)时,如果同时有多个其他线程持有读锁(共享锁),写锁的申请将会被阻塞,直到所有读锁都被释放。读锁和写锁之间的关系是互斥的:
- 当一个线程持有写锁时,其他任何线程都不能获得读锁或写锁。
- 当一个或多个线程持有读锁时,任何线程都不能获得写锁。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
#include <chrono>
std::shared_mutex sh_mtx;
std::vector<int> shared_data;
void reader(int id) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟读取前的延迟
std::shared_lock<std::shared_mutex> lock(sh_mtx); // 共享锁
std::cout << "Reader " << id << " is reading data: for (int num : shared_data) {
std::cout << num << " ";
}
std::cout << std::endl;
}
void writer(int id, int value) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟写入前的延迟
std::unique_lock<std::shared_mutex> lock(sh_mtx); // 独占锁
shared_data.push_back(value);
std::cout << "Writer " << id << " added value: " << value << std::endl;
}
int main() {
std::thread t1(reader, 1);
std::thread t2(reader, 2);
std::thread t3(writer, 3, 10);
std::thread t4(reader, 4);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
预期行为:
t1
和t2
线程几乎同时开始读取操作,并持有共享锁。t3
线程尝试获取独占锁(写锁),但由于t1
和t2
持有共享锁,t3
被阻塞。t1
和t2
完成读取操作并释放共享锁后,t3
才能获得写锁并进行写操作。t4
线程在t3
释放写锁后,才能继续持有共享锁并读取数据。
运行输出可能类似如下:
Reader 1 is reading data:Reader 2 is reading data:Writer 3 added value: 10
Reader 4 is reading data:10
在 C++ 中,类似于 Java 集合类的基本数据结构有许多选择,并且根据需要,可以选择线程安全或者线程不安全的实现。以下是一些主要的数据结构及其线程安全和线程不安全的实现方式:
1. std::vector
- 线程不安全:
std::vector
是一个动态数组,支持随机访问和快速索引。 - 线程安全:可以通过添加互斥锁(如
std::mutex
)来保护std::vector
的访问。
#include <vector>
#include <mutex>
std::vector<int> vec;
std::mutex mtx;
void safePushBack(int value) {
std::lock_guard<std::mutex> lock(mtx);
vec.push_back(value);
}
2. std::list
- 线程不安全:
std::list
是一个双向链表,适用于频繁插入和删除操作。 - 线程安全:同样可以使用互斥锁来保护对
std::list
的操作。
#include <list>
#include <mutex>
std::list<int> lst;
std::mutex mtx;
void safeAddToList(int value) {
std::lock_guard<std::mutex> lock(mtx);
lst.push_back(value);
}
3. std::set
和 std::unordered_set
- 线程不安全:
std::set
是一个有序集合,std::unordered_set
是一个无序集合。 - 线程安全:使用互斥锁来保护集合的修改。
#include <set>
#include <unordered_set>
#include <mutex>
std::set<int> orderedSet;
std::unordered_set<int> unorderedSet;
std::mutex mtx;
void safeInsertToSet(int value) {
std::lock_guard<std::mutex> lock(mtx);
orderedSet.insert(value);
unorderedSet.insert(value);
}
4. std::map
和 std::unordered_map
- 线程不安全:
std::map
是一个有序键值对集合,std::unordered_map
是一个无序键值对集合。 - 线程安全:使用互斥锁来保护对映射的修改。
#include <map>
#include <unordered_map>
#include <mutex>
std::map<int, int> orderedMap;
std::unordered_map<int, int> unorderedMap;
std::mutex mtx;
void safeInsertToMap(int key, int value) {
std::lock_guard<std::mutex> lock(mtx);
orderedMap[key] = value;
unorderedMap[key] = value;
}
5. boost::thread_safe
Boost 库提供了线程安全的数据结构,例如 boost::thread_safe::map
,可以直接使用而无需手动添加互斥锁。
#include <boost/thread_safe.hpp>
boost::thread_safe::map<int, int> threadSafeMap;
void safeInsertToBoostMap(int key, int value) {
threadSafeMap[key] = value;
}
总结
在 C++ 中,实现线程安全的集合类通常依赖于使用互斥锁来保护数据结构的访问。此外,使用 Boost 库可以简化一些实现。选择具体的数据结构时,需根据实际应用场景来决定,并根据是否需要线程安全来添加相应的保护措施。
在C++中,可以使用标准库中的std::thread
来创建和管理线程。下面将详细演示如何使用线程,包括线程的创建、同步、传递参数、返回值等方面。
基本线程创建
#include <iostream>
#include <thread>
void print_message(const std::string& message) {
std::cout << "Message: " << message << std::endl;
}
int main() {
std::thread t(print_message, "Hello, World!");
t.join(); // 等待线程完成
return 0;
}
线程同步
使用std::mutex
进行线程同步,以避免数据竞态。
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
std::vector<int> shared_data;
void add_to_vector(int value) {
std::lock_guard<std::mutex> lock(mtx);
shared_data.push_back(value);
std::cout << "Added value: " << value << std::endl;
}
int main() {
std::thread t1(add_to_vector, 1);
std::thread t2(add_to_vector, 2);
std::thread t3(add_to_vector, 3);
t1.join();
t2.join();
t3.join();
std::cout << "Vector size: " << shared_data.size() << std::endl;
return 0;
}
传递参数给线程
可以通过值传递、引用传递、以及使用std::ref
进行显式引用传递。
#include <iostream>
#include <thread>
#include <vector>
void modify_vector(std::vector<int>& vec) {
for (auto& val : vec) {
val *= 2;
}
}
int main() {
std::vector<int> data = {1, 2, 3, 4, 5};
std::thread t(modify_vector, std::ref(data));
t.join();
for (const auto& val : data) {
std::cout << val << " ";
}
std::cout << std::endl;
return 0;
}
从线程返回值
可以使用std::promise
和std::future
来从线程返回值。
#include <iostream>
#include <thread>
#include <future>
int calculate_square(int x) {
return x * x;
}
int main() {
std::promise<int> promise;
std::future<int> future = promise.get_future();
std::thread t([&promise]() {
int result = calculate_square(5);
promise.set_value(result);
});
t.join();
std::cout << "Result: " << future.get() << std::endl;
return 0;
}
使用std::async
std::async
可以简化线程创建和返回值处理。
#include <iostream>
#include <future>
int calculate_square(int x) {
return x * x;
}
int main() {
std::future<int> future = std::async(std::launch::async, calculate_square, 5);
std::cout << "Result: " << future.get() << std::endl;
return 0;
}
使用条件变量进行线程同步
条件变量(std::condition_variable
)可以让线程等待某个条件的满足。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
std::cout << "Thread " << id << std::endl;
}
void set_ready() {
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cv.notify_all();
}
int main() {
std::thread t1(print_id, 1);
std::thread t2(print_id, 2);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
set_ready();
t1.join();
t2.join();
return 0;
}
这些例子展示了C++中如何使用线程、互斥锁、条件变量、以及如何传递参数和返回值。通过这些技术,可以构建并发和多线程程序,以充分利用多核处理器的性能。
Boost 库中的重点数据结构
Boost 库是一个广泛使用的 C++ 库集合,其中包含许多实用的工具和数据结构。以下是 Boost 库中一些重点数据结构,尤其是涉及线程安全的部分:
1. boost::thread_safe
Boost 线程安全数据结构库提供了一些内置的线程安全容器,简化了并发编程。这些容器包括线程安全的 map
、set
等。
示例:boost::thread_safe::map
#include <boost/thread_safe/map.hpp>
boost::thread_safe::map<int, int> threadSafeMap;
void safeInsertToBoostMap(int key, int value) {
threadSafeMap[key] = value;
}
2. boost::container
Boost 容器库提供了一些增强版的标准容器,例如 vector
、list
、map
等,并且还包括一些标准库中没有的容器,例如 flat_map
。
示例:boost::container::flat_map
flat_map
是一种基于排序数组实现的关联容器,适用于键值对数量较少的情况,具有较好的缓存局部性。
#include <boost/container/flat_map.hpp>
boost::container::flat_map<int, int> flatMap;
void insertToFlatMap(int key, int value) {
flatMap[key] = value;
}
3. boost::lockfree
Boost 锁自由数据结构库提供了一些不需要锁的并发数据结构,例如 queue
和 stack
,这些数据结构使用原子操作来保证线程安全。
示例:boost::lockfree::queue
#include <boost/lockfree/queue.hpp>
#include <atomic>
boost::lockfree::queue<int> lockFreeQueue(128); // 128 是队列容量
std::atomic<int> producerCount(0);
std::atomic<int> consumerCount(0);
void producer(int value) {
if (lockFreeQueue.push(value)) {
producerCount++;
}
}
void consumer() {
int value;
if (lockFreeQueue.pop(value)) {
consumerCount++;
}
}
4. boost::intrusive
Boost 内嵌容器库提供了一些高效的容器,这些容器不管理元素的内存,而是将元素内嵌到容器中,适用于需要高性能和自定义内存管理的场景。
示例:boost::intrusive::list
#include <boost/intrusive/list.hpp>
using namespace boost::intrusive;
struct MyClass : public list_base_hook<> {
int value;
MyClass(int v) : value(v) {}
};
typedef list<MyClass> List;
List myList;
void addToList(MyClass &obj) {
myList.push_back(obj);
}
在这段代码中,void addToList(MyClass &obj)
函数中的 &obj
是一个引用(reference)类型的参数。引用是 C++ 中的一种数据类型,允许在函数中使用原始数据而不是副本,从而避免不必要的内存开销和提高性能。
具体来说,&obj
表示函数 addToList
接受一个指向 MyClass
类型对象的引用。当传递一个对象给这个函数时,实际上是传递了这个对象的引用,而不是对象的副本。这意味着在函数内部对 obj
的任何修改都会影响到原始对象,因为直接操作的是原始对象而不是它的副本。
使用引用作为函数参数通常有以下几个优点:
- 避免不必要的对象拷贝,提高性能。
- 允许函数修改传递进来的对象。
- 可以用来实现返回多个值的函数。
5. boost::multi_index
Boost 多重索引库允许在同一个容器中使用多个不同的索引方法,例如通过键值索引、通过排序索引等。
示例:boost::multi_index_container
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
using namespace boost::multi_index;
struct Employee {
int id;
std::string name;
Employee(int i, std::string n) : id(i), name(n) {}
};
typedef multi_index_container<
Employee,
indexed_by<
ordered_unique<member<Employee, int, &Employee::id>>,
ordered_non_unique<member<Employee, std::string, &Employee::name>>
>
> EmployeeContainer;
EmployeeContainer employees;
void addEmployee(int id, std::string name) {
employees.insert(Employee(id, name));
}
总结
C++中的lambda表达式是匿名函数,用于简洁地定义和使用函数对象。它们在C++11标准中引入,并在C++14和C++17中得到了进一步增强。下面通过几个示例详细演示lambda表达式的使用。
基本Lambda表达式
#include <iostream>
int main() {
auto greet = []() {
std::cout << "Hello, World!" << std::endl;
};
greet(); // 调用lambda表达式
return 0;
}
带参数的Lambda表达式
#include <iostream>
int main() {
auto add = [](int a, int b) {
return a + b;
};
int result = add(3, 4);
std::cout << "3 + 4 = " << result << std::endl;
return 0;
}
捕获外部变量
Lambda表达式可以捕获外部作用域的变量,有多种捕获方式:按值捕获、按引用捕获。
按值捕获
#include <iostream>
int main() {
int x = 10;
auto print_x = [x]() {
std::cout << "x = " << x << std::endl;
};
x = 20; // 修改x的值
print_x(); // 打印的仍是捕获时的x值
return 0;
}
按引用捕获
#include <iostream>
int main() {
int x = 10;
auto print_x = [&x]() {
std::cout << "x = " << x << std::endl;
};
x = 20; // 修改x的值
print_x(); // 打印的是修改后的x值
return 0;
}
捕获所有变量
可以使用=
或&
捕获所有变量,分别表示按值捕获和按引用捕获。
#include <iostream>
int main() {
int x = 10;
int y = 20;
auto print_all_by_value = [=]() {
std::cout << "x = " << x << ", y = " << y << std::endl;
};
auto print_all_by_reference = [&]() {
std::cout << "x = " << x << ", y = " << y << std::endl;
};
x = 30;
y = 40;
print_all_by_value(); // 打印捕获时的值
print_all_by_reference(); // 打印修改后的值
return 0;
}
Lambda与STL算法
Lambda表达式非常适合与STL算法一起使用,例如std::for_each
、std::sort
等。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用lambda表达式打印vector中的元素
std::for_each(vec.begin(), vec.end(), [](int n) {
std::cout << n << " ";
});
std::cout << std::endl;
// 使用lambda表达式对vector进行排序(降序)
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return b < a;
});
// 打印排序后的vector
std::for_each(vec.begin(), vec.end(), [](int n) {
std::cout << n << " ";
});
std::cout << std::endl;
return 0;
}
可变Lambda(mutable)
默认情况下,lambda表达式不能修改捕获的变量。如果需要修改,可以使用mutable
关键字。
#include <iostream>
int main() {
int x = 10;
auto increment_x = [x]() mutable {
x++;
std::cout << "x inside lambda = " << x << std::endl;
};
increment_x(); // 修改并打印x
std::cout << "x outside lambda = " << x << std::endl; // x的值未变
return 0;
}
Lambda作为线程的任务
Lambda表达式可以用于创建线程任务,非常简洁。
#include <iostream>
#include <thread>
int main() {
int x = 10;
std::thread t([x]() {
std::cout << "Thread x = " << x << std::endl;
});
t.join(); // 等待线程完成
return 0;
}
Lambda作为函数参数
Lambda表达式可以作为函数参数传递,用于回调函数等场景。
#include <iostream>
#include <vector>
#include <algorithm>
void apply_function(const std::vector<int>& vec, const std::function<void(int)>& func) {
for (int n : vec) {
func(n);
}
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
apply_function(vec, [](int n) {
std::cout << n << " ";
});
std::cout << std::endl;
return 0;
}
这些示例展示了lambda表达式在C++中各种场景下的应用,包括基本用法、捕获变量、与STL结合、线程任务以及作为函数参数等。通过灵活使用lambda表达式,可以编写更加简洁和高效的代码。